package com.example.jackson.util;

import com.example.jackson.dto.Result;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.JsonNodeType;

import java.io.IOException;
import java.io.InputStream;
import java.util.function.BiConsumer;

public class JacksonObject {
    public <T> T load(String path, TypeReference<T> typeRef) throws IOException {
        ObjectMapper mapper = new ObjectMapper();
        try (InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream(path)) {
            return mapper.readValue(is, typeRef);
        }
    }

    public <T> void visitTree(Result<T> result, BiConsumer<String, Integer> visitor) {
        ObjectMapper mapper = new ObjectMapper();
        JsonNode root = mapper.valueToTree(result);
        visit(root, 1, visitor);
    }

    public <T> void visitTree(String path, BiConsumer<String, Integer> visitor) throws IOException {
        ObjectMapper mapper = new ObjectMapper();
        try (InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream(path)) {
            JsonNode root = mapper.readTree(is);
            visit(root, 1, visitor);
        }
    }

    private void visit(JsonNode node, int depth, BiConsumer<String, Integer> visitor) {
        JsonNodeType type = node.getNodeType();
        visitor.accept(node.getClass().getSimpleName() + ":" + type.name() + ":" + node.toString(), depth);
        if (node.isObject()) {
            node.fields().forEachRemaining(e -> visit(e.getValue(), depth + 1, visitor));
        } else if (node.isArray()) {
            node.forEach(e -> visit(e, depth + 1, visitor));
        }
    }
}
